
#include "Analyser.h"

using namespace std;


const string Analyser::ALPHABETIC = 
      ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); 

const string Analyser::PRESERVED[]={"char","short","int","long","float",
										  "double","void","if","else","for",
										  "while","class","private","public",
										  "const","virtual"};

//*****************************************************************************
//Constructor from Parser object
//*****************************************************************************
Analyser::Analyser(const InputLine& inp):
	inputLine(inp) 
{
	rBrackets = 0;
	sBrackets = 0;
	cBrackets = 0;
	ifElse    = 0;
	multiple  = 0;

}

//*****************************************************************************
//copy CTOR
//*****************************************************************************
Analyser::Analyser(const Analyser& anl):
	inputLine(anl.inputLine)
{
	declaration = anl.declaration;
	
	rBrackets = 0;
	sBrackets = 0;
	cBrackets = 0;
	ifElse    = 0;
	multiple  = 0;

}

//*****************************************************************************
//assignment operator
//*****************************************************************************
const Analyser& Analyser::operator=(const Analyser& anl)
{
	if (this != &anl)
	{
		inputLine = anl.inputLine;
		declaration = anl.declaration;
		
		rBrackets = anl.rBrackets;
		sBrackets = anl.sBrackets;
		cBrackets = anl.cBrackets;
		ifElse    = anl.ifElse;
		multiple  = anl.multiple;

	}

	return *this;
}


//*****************************************************************************
//Check the syntax of each input line and report mistakes
//*****************************************************************************
void Analyser::doAnalyse()
{
	int lineNum = 1;
	
	vector<vector<string>>::iterator extIt;
	vector<string>::iterator intIt;
	vector<string>::iterator prev;
	vector<vector<string>> tmp = inputLine.getFileTokens();

	extIt = tmp.begin();

	while (extIt != tmp.end())
	{
		intIt = (*extIt).begin();
		

		while (intIt != (*extIt).end())
		{
			// checking first rule (brackets) A
			if (  *intIt == "(" || *intIt == ")" || *intIt == "{" ||
				  *intIt == "}" || *intIt == "[" || *intIt == "]"    )
				checkBracketsA(*intIt, lineNum);

			// checking second rule (if-else)
			if ( *intIt == "if" || *intIt == "else")
				checkIfElse(*intIt, lineNum);

			// checking fourth rule (already declared)
			if ( multiple > 0) 
			{
				checkAlreadyDeclared(*intIt, lineNum);
			}
			// checking third rule (multiple predefined types)
			if ( *intIt == "char" || *intIt == "short" || *intIt == "int" || *intIt == "long" ||
				 *intIt == "float" || *intIt == "double" || *intIt == "void")
			{
				checkMultiplePredefined(*intIt, lineNum);
			}
			else
				multiple = 0;

			// checking identifier second rule(token wasn't declared before)
			if (*intIt == "=")
			{
			  checkIdentifierDeclare(*intIt,*prev,lineNum);
			}

			//save prev token
			prev = intIt;
			// move to the next token
			intIt++; 
		}
		//check if the last token in line violate identifier rule
		if(*prev == "char" || *prev == "short" || *prev == "int" || *prev == "long" ||
				 *prev == "float" || *prev == "double" || *prev == "void")
				cout << "line " << lineNum << ": identifiers rule violation" << endl;

		// move to the next line
		extIt++;
		lineNum++;
		multiple = 0;
	}

	// checking first rule (brackets) B 
	checkBracketsB();

}

//*****************************************************************************
//Checking first rule violation (brackets) before the end of the line 
//*****************************************************************************
void Analyser::checkBracketsA(const string token, int lineNum)
{
	if (token == "(") rBrackets++;
	if (token == ")") rBrackets--;
	if (token == "[") sBrackets++;
	if (token == "]") sBrackets--;
	if (token == "{") cBrackets++;
	if (token == "}") cBrackets--;

	if (rBrackets<0)
	{
		cout << "line " << lineNum << ": brackets rule violation -";
		cout << " ')' before '('" << endl;
		rBrackets++;
	}

	if (sBrackets<0)
	{
		cout << "line " << lineNum << ": brackets rule violation -";
		cout << " ']' before '['" << endl;
		sBrackets++;
	}

	if (cBrackets<0)
	{
		cout << "line " << lineNum << ": brackets rule violation -";
		cout << " '}' before '{'" << endl;
		cBrackets++;
	}

}

//*****************************************************************************
//Checking first rule violation (brackets)  - opened==closed 
//*****************************************************************************
void Analyser::checkBracketsB() const
{
	if (rBrackets>0 || sBrackets>0 || cBrackets>0)
	{
		cout << "file : brackets rule violation -";
		cout << " opened not equel to closed" << endl;
	}
}

//*****************************************************************************
//Checking second rule (if-else)
//*****************************************************************************
void Analyser::checkIfElse(const string token, int lineNum)
{
	if (token == "if") ifElse++;
	if (token == "else") ifElse--;

	if (ifElse<0)
	{
		cout << "line " << lineNum << ": if-else rule violation";
		cout << " (else before if)" << endl;

		ifElse++;
	}
}

//*****************************************************************************
//Checking third rule violation (multiple predefined types)   
//*****************************************************************************
void Analyser::checkMultiplePredefined(const string token, int lineNum)
{
	if (multiple>0)
	{
		cout << "line " << lineNum << ": multiple Predefined rule violation" << endl;;
	}

	multiple++;
}

//*****************************************************************************
//Checking fourth rule violation (already declared)   
//*****************************************************************************
void Analyser::checkAlreadyDeclared(const string token, int lineNum)
{
	size_t alphabetic;
	int preserved = 0;
	
	for (int i=0;i<ARRAY_SIZE;++i)
	{
		if(!PRESERVED[i].compare(token))
		{
			preserved = 1;
			cout << "line " << lineNum << ": identifiers rule violation" << endl;
		}
	}
	alphabetic=token.find_first_of(ALPHABETIC);
	if(alphabetic!=0) //first rule of identifier - don't start whith alphabetic char
		cout << "line " << lineNum << ": identifiers rule violation" << endl;
	if ((preserved==0)&&(alphabetic==0)&& (multiple==1))
	{
		if (declaration[token]==0)
		{
			declaration[token]++;
		}
		else
			cout << "line " << lineNum << ": already declared rule violation" << endl;
	}

}

//*************************************************************************
//checking identifier second rule(token wasn't declared before)  
//*************************************************************************
void Analyser::checkIdentifierDeclare(const string token,const string prev,int lineNum)
{
	int preserved = 0;
	size_t alphabetic;
	alphabetic=prev.find_first_of(ALPHABETIC);
	if(alphabetic!=0)  
		return;//prev don't start whith alphabetic char , for example "12abc = 5" is ligal
	
	for (int i=0;i<ARRAY_SIZE;++i)
	{
		if(!PRESERVED[i].compare(prev))
		return; //prev is preserve word, for example "if=5" is ligal
	}
	if (declaration[prev]==0) // prev wasn't declared before
		{
			cout << "line " << lineNum << ": token wasn't declared before" << endl;
		}
		
}

//*****************************************************************************
//DTOR
//*****************************************************************************
Analyser::~Analyser(void)
{
}
